﻿using System;
using System.Media;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Animation;

using Writespace.Dialogs.Properties;

namespace Writespace.Dialogs
{
    public partial class TextEditorWindow : Window
    {
        public delegate void SaveEventHandler(object sender, EventArgs e);
        public event SaveEventHandler Save;
        public delegate void OpenEventHandler(object sender, EventArgs e);
        public event OpenEventHandler Open;
        public delegate void ToggleMonitorEventHandler(object sender, EventArgs e);
        public event ToggleMonitorEventHandler ToggleMonitor;

        private bool _controlPressed;
        private int _fontSize = 16;

        public TextEditorWindow()
        {
            InitializeComponent();
        }

        #region Props

        public bool IsModified { get; set; }

        public string ParentId { get; set; }

        public string Text
        {
            get { return MyTextBox.Text; }
            set
            {
                MyTextBox.Text = value;
                UpdateRowCol(true);
            }
        }

        public string EditorLanguage
        {
            get
            {
                return MyTextBox.Language.IetfLanguageTag;
            }
            set
            {
                if (!string.IsNullOrEmpty(value))
                {
                    MyTextBox.Language = XmlLanguage.GetLanguage(value);
                    MyTextBox.SpellCheck.IsEnabled = true;
                }
                else
                    MyTextBox.SpellCheck.IsEnabled = false;
            }
        }

        public string Status
        {
            set
            {
                StatusLabel.Content = value;
                AnimateControl(StatusLabel, TimeSpan.FromSeconds(4));
            }
        }

        #endregion

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {

            ApplyValuesFromSettings();

            MyTextBox.Focus();
            Status = "";
            UpdateRowCol(true);

        }


        private void ApplyValuesFromSettings()
        {
            try
            {
                TopRow.Height = new GridLength(Settings.Default.MarginTop);
                MyTextBox.FontSize = _fontSize = Settings.Default.FontSize;
                MyTextBox.FontFamily = new FontFamily(Settings.Default.FontFamily);
                Column1.Width = (GridLength)new GridLengthConverter().ConvertFromString(Settings.Default.Margin);
                Column1.MaxWidth = ActualWidth / 3;
                MyTextBox.Background = (SolidColorBrush)new BrushConverter().ConvertFromString(Settings.Default.BackgroundColor);
                MyTextBox.Foreground = (SolidColorBrush)new BrushConverter().ConvertFromString(Settings.Default.Color);
                MyTextBox.CaretBrush = (SolidColorBrush)new BrushConverter().ConvertFromString(Settings.Default.Color);
                MyTextBox.TextAlignment = (TextAlignment)Enum.Parse(typeof(TextAlignment), Settings.Default.TextAlign);
                EditorLanguage = Settings.Default.Language;

            }
            catch (Exception e)
            {
                MessageBox.Show(e.ToString());
            }
        }

        #region Control Events

        private void MyTextBox_KeyDown(object sender, KeyEventArgs e)
        {
            if (_controlPressed)
            {
                switch (e.Key)
                {
                    case Key.F:
                        ShowSearchDialog();
                        _controlPressed = false;
                        e.Handled = true;
                        break;
                    case Key.G:
                        ShowGotoDialog();
                        _controlPressed = false;
                        e.Handled = true;
                        break;
                    case Key.M: //toggle monitor modes
                        ToggleMonitor(this, null);
                        _controlPressed = false;
                        e.Handled = true;
                        break;
                    case Key.S:
                        Save(this, null);
                        _controlPressed = false;
                        e.Handled = true;
                        break;
                    case Key.O:
                        Open(this, null);
                        _controlPressed = false;
                        e.Handled = true;
                        break;
                }
            }
            else
            {
                switch (e.Key)
                {
                    case Key.F4:
                        ShowOptionsDialog();
                        return;
                    case Key.F3:
                        if (!string.IsNullOrEmpty(_searchFor))
                            Search();
                        else
                            ShowSearchDialog();
                        return;
                    case Key.LeftCtrl:
                        _controlPressed = true;
                        return;
                    case Key.RightCtrl:
                        _controlPressed = true;
                        return;
                    case Key.Escape:
                        Close();
                        return;
                }

                IsModified = true;
            }
        }

        private void MyTextBox_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            UpdateRowCol(false);
        }

        private void UpdateRowCol(bool animate)
        {
            var lineIndex = MyTextBox.GetLineIndexFromCharacterIndex(MyTextBox.CaretIndex);
            var col = MyTextBox.CaretIndex - MyTextBox.GetCharacterIndexFromLineIndex(lineIndex);
            var words = MyTextBox.Text.WordCount();
            RowCol.Content = string.Format("Ln {0} Col {1} Words {2}", lineIndex + 1, col + 1, words);

            if (animate) AnimateControl(RowCol, TimeSpan.FromSeconds(1.5));
        }

        private void MyTextBox_KeyUp(object sender, KeyEventArgs e)
        {
            UpdateRowCol(false);

            if (e.Key == Key.LeftCtrl || e.Key == Key.RightCtrl)
                _controlPressed = false;
        }

        private void MyTextBox_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
        {
            if (!_controlPressed) return;

            if (e.Delta > 0 && _fontSize < 64)
                _fontSize += 2;
            if (e.Delta < 0 && _fontSize > 6)
                _fontSize -= 2;

            MyTextBox.FontSize = _fontSize;
            Settings.Default.FontSize = _fontSize;
            Settings.Default.Save();

            e.Handled = true;
        }

        private void MyTextBox_MouseDown(object sender, MouseButtonEventArgs e)
        {
            UpdateRowCol(false);
        }

        #endregion

        #region Options

        private void ShowOptionsDialog()
        {
            var options = new OptionsWindow();
            var res = options.ShowDialog();
            if (res == false)
                Settings.Default.Reload();

            ApplyValuesFromSettings();
        }

        #endregion

        #region Search

        private string _searchFor;

        private void MyTextBox_GotFocus(object sender, RoutedEventArgs e)
        {
            _controlPressed = false;
            SearchPanel.Visibility = Visibility.Hidden;
        }

        private void SearchButton_Click(object sender, RoutedEventArgs e)
        {
            SearchPanel.Visibility = Visibility.Hidden;
            MyTextBox.Focus();
            _searchFor = SearchBox.Text;
            Search();
        }

        private void SearchBox_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
                SearchButton_Click(null, null);

            if (e.Key == Key.Escape)
            {
                _controlPressed = false;
                SearchPanel.Visibility = Visibility.Hidden;
                MyTextBox.Focus();
            }
        }

        private void ShowSearchDialog()
        {
            if (!string.IsNullOrEmpty(MyTextBox.SelectedText))
                SearchBox.Text = MyTextBox.SelectedText;
            SearchBox.SelectAll();

            SearchPanel.Margin = new Thickness(ActualWidth / 2 - 150, ActualHeight / 2 - 75, 0, 0);
            SearchPanel.Visibility = Visibility.Visible;
            SearchBox.Focus();
        }

        private void Search()
        {
            //search from cursor position
            var startIndex = MyTextBox.CaretIndex + 1;
            if (startIndex > MyTextBox.Text.Length) startIndex = MyTextBox.Text.Length; //sanity check

            var pos = MyTextBox.Text.ToLowerInvariant()
                .IndexOf(_searchFor.ToLowerInvariant(), startIndex);
            if (pos > MyTextBox.CaretIndex)
            {
                MyTextBox.Select(pos, _searchFor.Length);
                return;
            }

            //no hit, search from beginning
            pos = MyTextBox.Text.ToLowerInvariant()
                .IndexOf(_searchFor.ToLowerInvariant(), 0);
            if (pos > -1)
            {
                MyTextBox.Select(pos, _searchFor.Length);
                return;
            }

            //not found
            SystemSounds.Beep.Play();
        }

        #endregion

        #region Goto

        private void ShowGotoDialog()
        {
            GotoPanel.Margin = new Thickness(ActualWidth / 2 - 150, ActualHeight / 2 - 75, 0, 0);
            GotoBox.Text = "";
            GotoPanel.Visibility = Visibility.Visible;
            GotoBox.Focus();
        }

        private void GotoBox_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
                GotoButton_Click(null, null);

            if (e.Key == Key.Escape)
            {
                _controlPressed = false;
                GotoPanel.Visibility = Visibility.Hidden;
                MyTextBox.Focus();
            }
        }

        private void GotoButton_Click(object sender, RoutedEventArgs e)
        {
            int lineWanted;
            if (!Int32.TryParse(GotoBox.Text, out lineWanted))
            {
                SystemSounds.Exclamation.Play();
                return;
            }

            lineWanted--;
            if (lineWanted > MyTextBox.LineCount)
            {
                SystemSounds.Exclamation.Play();
                return;
            }
            MyTextBox.CaretIndex = MyTextBox.GetCharacterIndexFromLineIndex(lineWanted);
            GotoPanel.Visibility = Visibility.Hidden;
            MyTextBox.Focus();
            UpdateRowCol(true);
        }

        #endregion

        #region Splitter events

        private void Splitter_DragCompleted(object sender, System.Windows.Controls.Primitives.DragCompletedEventArgs e)
        {
            Settings.Default.Margin = Column1.Width.Value.ToString();
            Settings.Default.Save();
            MyTextBox.Focus();
        }

        private void Splitter_MouseEnter(object sender, MouseEventArgs e)
        {
            var bgBrush = new SolidColorBrush(Colors.Transparent);
            var animation = new ColorAnimation
                {
                    Duration = new Duration(TimeSpan.FromSeconds(0.5)),
                    To = (Color)ColorConverter.ConvertFromString(Settings.Default.Color)
                };
            bgBrush.BeginAnimation(SolidColorBrush.ColorProperty, animation);
            Splitter.Background = bgBrush;
        }

        private void Splitter_MouseLeave(object sender, MouseEventArgs e)
        {
            var bgBrush = new SolidColorBrush((Color)ColorConverter.ConvertFromString(Settings.Default.Color));
            var animation = new ColorAnimation
            {
                Duration = new Duration(TimeSpan.FromSeconds(1.5)),
                To = Colors.Transparent
            };
            bgBrush.BeginAnimation(SolidColorBrush.ColorProperty, animation);
            Splitter.Background = bgBrush;
        }

        #endregion

        #region Animations

        private static void AnimateControl(Control label, TimeSpan time)
        {
            var color = (Color)ColorConverter.ConvertFromString(Settings.Default.Color);
            var foreground = new SolidColorBrush(color);
            var animation = new ColorAnimation
            {
                Duration = new Duration(time),
                From = color,
                To = Colors.Transparent
            };
            foreground.BeginAnimation(SolidColorBrush.ColorProperty, animation);
            label.Foreground = foreground;
        }

        #endregion
    }
}
